package com.atguigu.mq.config;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class MyConfirmConfig implements RabbitTemplate.ReturnCallback, RabbitTemplate.ConfirmCallback {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    // 这个初始化方法的总目标，就是为了给 rabbitTemplate 装配当前类的对象
    // 修饰一个非静态的 void()方法，在服务器加载 Servlet 的时候运行，并且只会被服务器执行一次。
    // 具体是在构造器之后、init()方法之前执行。
    @PostConstruct
    public void doInit() {
        // 当前配置类对象作为 ConfirmCallback 类型的实例装配给 RabbitTemplate
        rabbitTemplate.setConfirmCallback(this);

        // 当前配置类对象作为 ReturnCallback 类型的实例装配给 RabbitTemplate
        rabbitTemplate.setReturnCallback(this);
    }

    /**
     * 回调函数：用于确认消息是否发送到了交换机
     * @param correlationData 与本次消息发送相关的参数
     * @param ack 表示消息是否发送到了交换机
     *            true：发送到了
     *            false：没有发送到
     * @param cause 如果发送到交换机失败，那么原因是什么
     */
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            System.out.println("[生产者]消息发送到了交换机。 correlationData = " + correlationData);
        } else {
            System.out.println("[生产者]消息未发送到交换机。 correlationData = " + correlationData + " cause = " + cause);
        }
    }

    /**
     * 没有发送到队列时才会来调用这个方法
     * @param message 要发送到队列的消息
     * @param replyCode 响应状态码
     * @param replyText 响应状态码的说明文本
     * @param exchange 交换机名称
     * @param routingKey 路由键
     */
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        System.out.println("[生产者] message = " + new String(message.getBody()));
        System.out.println("[生产者] replyCode = " + replyCode);
        System.out.println("[生产者] replyText = " + replyText);
        System.out.println("[生产者] exchange = " + exchange);
        System.out.println("[生产者] routingKey = " + routingKey);
    }
}
